/*
 * linda_tests.cpp
 * Author: Michal Kolodziejski
 */

/*
 * g++ -o linda_tests tests/linda_tests.cpp build/Release/GNU-Linux-x86/Linda.o build/Release/GNU-Linux-x86/Server.o build/Release/GNU-Linux-x86/TMessage.o -llog4cxx -lboost_thread -lboost_regex
 */

#define BOOST_TEST_MODULE linda library tests

#include <boost/test/included/unit_test.hpp>
#include <boost/shared_ptr.hpp>
#include <log4cxx/logger.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/helpers/exception.h>
#include <sstream>
#include <stdlib.h>
#include <time.h>
#include "../Linda.h"
#include "../standardLindaHeaders.h"

using namespace boost::unit_test;

LoggerPtr logger(Logger::getLogger("LindaTests"));

int queueId = -1;

struct LindaFixture {
    LindaFixture(){
        // set up
        PropertyConfigurator::configure("log4cxx-tests.config");
        LOG4CXX_INFO(logger, "Starting test...");

        if(queueId == -1){
            srand(time(NULL));
            queueId = rand() % 100000;
        } else {
            ++queueId;
        }
        linda1 = boost::shared_ptr<Linda>(new Linda(queueId));
        linda2 = boost::shared_ptr<Linda>(new Linda(queueId));
    }

    ~LindaFixture(){
        // clean up
        LOG4CXX_INFO(logger, "Test finished - cleaning up");
        linda1.reset();
        linda2.reset();
    }

    boost::shared_ptr<Linda> linda1, linda2;
};



BOOST_FIXTURE_TEST_SUITE( linda_tests, LindaFixture )


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(string:\"tekst\",integer:==123)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive2 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(string:*,integer:*)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive3 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(*:*,*:*)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive4 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(string:>\"tek\",integer:>122)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive5 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(string:<\"tekstowo\",integer:<125)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive6 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(*:\"tekst\",*:123)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive7 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(*:==\"tekst\",*:==123)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive8 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(*:<\"tekstttttt\",*:<125)", 1);
        BOOST_CHECK( result == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_send_and_receive9 ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",-123)");
        std::string result = linda2->input("(*:<=\"tekst\",*:>-125)", 1);
        BOOST_CHECK( result == "(\"tekst\",-123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_multiple_read ){
    bool exceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result1 = linda2->read("(string:*,integer:==123)", 1);
        std::string result2 = linda2->read("(string:==\"tekst\",integer:*)", 1);
        std::string result3 = linda2->read("(string:==\"tekst\",integer:==123)", 1);
        std::string result4 = linda2->read("(*:*,*:*)", 1);
        BOOST_CHECK( result1 == "(\"tekst\",123)" );
        BOOST_CHECK( result2 == "(\"tekst\",123)" );
        BOOST_CHECK( result3 == "(\"tekst\",123)" );
        BOOST_CHECK( result4 == "(\"tekst\",123)" );
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == false );
}


BOOST_AUTO_TEST_CASE( linda_test_multiple_input ){
    bool exceptionOccured = false;
    bool timeoutExceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result1 = linda2->input("(string:*,integer:*)", 1);
        BOOST_CHECK( result1 == "(\"tekst\",123)" );
        std::string result4 = linda2->input("(*:*,*:*)", 3);
    } catch (LindaTimeoutException &e){
        exceptionOccured = true;
        timeoutExceptionOccured = true;
    } catch (const LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( timeoutExceptionOccured == true );
}


BOOST_AUTO_TEST_CASE( linda_test_timeout1 ){
    bool exceptionOccured = false;
    bool timeoutExceptionOccured = false;
    try {
        linda1->output("(\"tekst\",123)");
        std::string result = linda2->input("(integer:*,integer:*)", 1);
    } catch (LindaTimeoutException &e){
        exceptionOccured = true;
        timeoutExceptionOccured = true;
    } catch (LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( timeoutExceptionOccured == true );
}


BOOST_AUTO_TEST_CASE( linda_test_malformed_msg1 ){
    bool exceptionOccured = false;
    bool malformedMessageExceptionOccured = false;
    try {
        linda1->input("cokolwiek", 1);
    } catch (LindaMalformedMessageException &e){
        exceptionOccured = true;
        malformedMessageExceptionOccured = true;
    } catch (LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( malformedMessageExceptionOccured == true );
}


BOOST_AUTO_TEST_CASE( linda_test_malformed_msg2 ){
    bool exceptionOccured = false;
    bool malformedMessageExceptionOccured = false;
    try {
        linda1->input("()", 1);
    } catch (LindaMalformedMessageException &e){
        exceptionOccured = true;
        malformedMessageExceptionOccured = true;
    } catch (LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( malformedMessageExceptionOccured == true );
}


BOOST_AUTO_TEST_CASE( linda_test_malformed_msg3 ){
    bool exceptionOccured = false;
    bool malformedMessageExceptionOccured = false;
    try {
        linda1->input("(\"tekst\")", 1);
    } catch (LindaMalformedMessageException &e){
        exceptionOccured = true;
        malformedMessageExceptionOccured = true;
    } catch (LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( malformedMessageExceptionOccured == true );
}


BOOST_AUTO_TEST_CASE( linda_test_malformed_msg4 ){
    bool exceptionOccured = false;
    bool malformedMessageExceptionOccured = false;
    try {
        linda1->input("(string:tekst)", 1);
    } catch (LindaMalformedMessageException &e){
        exceptionOccured = true;
        malformedMessageExceptionOccured = true;
    } catch (LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( malformedMessageExceptionOccured == true );
}


BOOST_AUTO_TEST_CASE( linda_test_malformed_msg5 ){
    bool exceptionOccured = false;
    bool malformedMessageExceptionOccured = false;
    try {
        linda1->input("(integer:123tekst)", 1);
    } catch (LindaMalformedMessageException &e){
        exceptionOccured = true;
        malformedMessageExceptionOccured = true;
    } catch (LindaException &e){
        exceptionOccured = true;
    }
    BOOST_CHECK( exceptionOccured == true );
    BOOST_CHECK( malformedMessageExceptionOccured == true );
}



BOOST_AUTO_TEST_SUITE_END()
